use super::{
    err, err_value, json, throw_err, Base, Client, ECode, MapSv, TBase, VBase, VMap, Value,
};

pub struct Cfg {
    line: String,
    sel_sn: String,
}

impl Base for Cfg {}
impl TBase for Cfg {}

impl Cfg {
    pub fn new(line: &str, sel_sn: &str) -> Self {
        Self {
            line: line.to_string(),
            sel_sn: sel_sn.to_string(),
        }
    }

    pub fn pos(&self, data: &MapSv) -> Result<MapSv, Value> {
        let tp = data.ck_str("tp")?;

        let mut ret = MapSv::new();

        ret.insert("line".to_string(), json!(self.line));
        ret.insert("sel".to_string(), json!(self.sel_sn));
        ret.insert("tp".to_string(), json!(tp));

        match tp {
            "inner" => {
                let inner = data.ck_bool("inner").unwrap_or(false);
                let inner_s = data.ck_bool("inner_s").unwrap_or(false);
                let inner_e = data.ck_bool("inner_e").unwrap_or(false);

                ret.insert("inner".to_string(), json!(inner));
                ret.insert("inner_s".to_string(), json!(inner_s));
                ret.insert("inner_e".to_string(), json!(inner_e));
            }
            "outer" => {
                let outer = data.ck_bool("outer").unwrap_or(false);
                let outer_s = data.ck_bool("outer_s").unwrap_or(false);
                let outer_e = data.ck_bool("outer_e").unwrap_or(false);

                ret.insert("outer".to_string(), json!(outer));
                ret.insert("outer_s".to_string(), json!(outer_s));
                ret.insert("outer_e".to_string(), json!(outer_e));
            }
            _ => throw_err!(ECode::Para, "tp error"),
        }

        Ok(ret)
    }

    pub fn outer_box(&self, data: &MapSv) -> Result<Vec<String>, Value> {
        let tmp = data.ck_array("outer")?;

        let mut ret = Vec::new();

        for d in tmp.iter() {
            let d = d.ckstr()?;
            ret.push(d.to_string());
        }

        Ok(ret)
    }

    pub fn inner_box(&self, data: &MapSv) -> Result<Vec<String>, Value> {
        let tmp = data.ck_array("inner")?;

        let mut ret = Vec::new();

        for d in tmp.iter() {
            let d = d.ckstr()?;
            ret.push(d.to_string());
        }

        Ok(ret)
    }

    pub fn get_ip(&self, data: &MapSv) -> Result<String, Value> {
        let ip = data.ck_str("ip")?;
        Ok(ip.to_string())
    }

    pub async fn get(&self, client: &Client) -> Result<MapSv, Value> {
        let cmd = json!({ "line": self.line });

        let body = client
            .cfgdb(&cmd, &format!("file/get/select_{}", self.sel_sn))
            .await?;
        let body = body.ck_obj("data")?;

        Ok(body.clone())
    }
}
